import socket
import threading
import time
import CPU
import pickle
from inter_status import InterStatus
##选择服务器发送代码



class chooseSendThread(threading.Thread):
    def __init__(self, performance, cpuNumber, sock):
        threading.Thread.__init__(self)
        self.performance = performance
        self.cpuNumber = cpuNumber
        self.sock = sock

    def run(self):
        global isBest
        global stop
        global i
        i = 0
        isBest = True
        stop = False
        global event
        while not stop:
            i += 1

            self.sock.sendto(("%s|" % i + "%s|" % self.performance + "%s" % self.cpuNumber).encode('utf-8'),
                             ('255.255.255.255', 2201))
            print("%s|" % i + "%s|" % self.performance + "%s" % self.cpuNumber)
            if i >= 6:
                self.sock.sendto("yes".encode('utf-8'), ('255.255.255.255', 2200))
                event.set()
                stop = True
            time.sleep(2)
        print("finish send")

    # 选择服务器接收处理代码


class chooseReceiveThread(threading.Thread):
    def __init__(self, performance, cpuNumber, sock):
        threading.Thread.__init__(self)
        self.performance = performance
        self.cpuNumber = cpuNumber
        self.sock = sock

    def run(self):
        global isBest
        global stop
        global i
        isBest = True
        stop = False
        global serverHost
        global addrs
        minPer = self.performance
        maxNum = self.cpuNumber
        addrs = []
        while True:
            data, addr = self.sock.recvfrom(5120)
            if addr not in addrs:
                addrs.append(addr)
            message = data.decode('utf-8')
            message = message.split('|')
            # 让服务端主机停止发送
            if message[0] == "ok" or message[0] == 'yes':
                stop = True
                if message[0] == "ok":
                    addStr = message[1].split(',')
                    addStr[0] = addStr[0].strip('(')
                    addStr[0] = addStr[0].strip("'")
                    addStr[1] = addStr[1].strip(')')
                    address = (addStr[0], int(addStr[1]))
                    serverHost = address
                else:
                    serverHost = addr
                break
            # 发送停止信息给服务器主机
            if int(message[0]) >= 20:
                self.sock.sendto('ok|'.encode('utf-8') + str(addr).encode('utf-8'), addr)
                serverHost = addr
                # print(serverHost)
                break
            if minPer > float(message[1]):
                minPer = float(message[1])
            elif minPer == float(message[1]):
                if self.cpuNumber < float(message[2]):
                    minPer = float(message[1])
                    maxNum = float(message[2])
                elif self.cpuNumber == float(message[2]):
                    if float(message[0]) > i:
                        isBest = False
                        stop = True
                        pass
            if (self.performance != minPer) or (self.cpuNumber != maxNum):
                isBest = False
                stop = True
        print("finish receive")
        print("addrs:", end="")
        for addr in addrs:
            print(addr)
        if isBest:
            print("i am the serverHost")
            print("serverHost is:", end="")
            print(serverHost)
        else:
            print("serverHost is:", end="")
            print(serverHost)
        event.set()


# 主服务主机


class serverSendOwn(threading.Thread):
    def __init__(self, serverHost):
        threading.Thread.__init__(self)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.sock.bind(('0.0.0.0', 2500))
        self.addr = serverHost

    def run(self):
        while True:
            self.sock.sendto(('host|' + str(self.addr)).encode('utf-8'), ('255.255.255.255', 2501))
            self.sock.sendto(('host|' + str(self.addr)).encode('utf-8'), ('255.255.255.255', 2502))
            time.sleep(6)


class startServerHost(threading.Thread):
    def __init__(self, serverHost):
        threading.Thread.__init__(self)
        self.clients = []
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(serverHost)
        self.sock.listen(10)
        print("waitting for connection")

    def run(self):
        global clientAccount
        global clients
        global serving
        global events
        global receiveRo
        global compare
        global carAccount
        global clientSock
        global livingCar
        global carSock
        global carMac
        carMac = []
        carSock = []
        clientSock = []
        compare = []
        receiveRo = []
        events = []
        clients = []
        clientAccount = 0
        carAccount = 0
        carId = -1
        clientid = 0
        serving = []
        while True:
            print("hello")
            newSock, client = self.sock.accept()
            data = newSock.recv(5120)
            message = data.decode('utf-8')
            message = message.split('|')
            if message[0] == 'car':
                if (int(message[1]) != -1) or (message[2] in carMac):
                    if int(message[1]) != -1:
                        carId = int(message[1])
                    else:
                        carId = carMac.index(message[2])
                    serving[carId] = '0.0.0.0'
                else:
                    while carId in livingCar:
                        carId += 1
                if carId == -1:
                    carId += 1
                print('收到一个车辆连接：%s:%s' % client)
                newSock.send(('you|' + '%s' % carId).encode('utf-8'))
                carAccount += 1
                livingCar.append(carId)
                print("现有车辆数：%s" % carAccount)
                while len(events) <= carId:
                    event = threading.Event()
                    events.append(event)
                    clientround = ReceiveRound()
                    receiveRo.append(clientround)
                    compare.append([])
                    serving.append([])
                    carSock.append([])
                    carStatus.append([])
                    carMac.append([])
                carStatus[carId] = InterStatus()
                carStatus[carId].address = client[0]
                carSock[carId] = client
                carMac[carId] = message[2]
                threading.Thread(target=tcpserverReCar, args=(newSock,)).start()
                if clientSock:
                    for sock in clientSock:
                        sock.send(("analysis|" + "%s|" % carId).encode('utf-8'))
                        sock.send(('cars|' + '%s|' % carId + '%s|' % str(client)).encode('utf-8'))
            else:
                clients.append(client)
                clientSock.append(newSock)
                print('收到一个客户端连接：%s:%s' % client)
                newSock.send(('id|' + '%s' % clientid).encode('utf-8'))
                clientAccount += 1
                print("现有客户端数：%s" % clientAccount)
                clientid += 1
                threading.Thread(target=tcpserverReCli, args=(newSock,)).start()
                if carAccount != 0:
                    for cd in livingCar:
                        newSock.send(("analysis|" + "%s|" % cd).encode('utf-8'))


global clientAccount
global clients
global serving
global events
global receiveRo
global compare
global hostDelay
global carAccount
global clientSock
global livingCar
global carSock
global carMac
livingCar = []


class getCarStatusSer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(("127.0.0.1", 5200))
        self.sock.listen(10)

    def run(self):
        global carStatus
        global clientSock

        while True:
            sock, client = self.sock.accept()

            def __get_car_status_ser():
                while True:
                    try:
                        data = sock.recv(1024)
                    except Exception:
                        print("接收status出现异常")
                        sock.close()
                        break
                    if data:
                        theStatus = pickle.loads(data)
                        if type(theStatus) == str:
                            # print('hit')
                            # print(f'theStatus = {theStatus}')
                            message = theStatus.split('|')

                            if message[0] == 'status':
                                print(message[1])
                                for car in carStatus:
                                    print(car.address)
                                    if car.address == message[1]:
                                        sock.send(car.encodes())
                                        break
                        else:
                            print(theStatus.id)
                            for car in carSock:
                                print(car[0])
                                print(theStatus.address)
                                if car[0] == theStatus.address:
                                    theStatus.id = carSock.index(car)
                                    carStatus[theStatus.id] = theStatus
                                    print(carStatus[theStatus.id].change())
                                    if clientSock:
                                        for socks in clientSock:
                                            socks.send(('status|' + theStatus.change()).encode('utf-8'))
                                        print("发送")
                                    break

            threading.Thread(target=__get_car_status_ser).start()


class ReceiveRound:
    def __init__(self):
        self.servernum = 0
        self.receiveround = 1
        self.arrival = 0


def tcpserverReCar(so):
    global receiveRo
    global serving
    global carAccount
    global clientAccount
    global hostDelay
    global clients
    global compare
    global serverHost
    global events
    global carSock
    global livingCar
    while True:
        try:
            data = so.recv(1024)
            message = data.decode('utf-8')
            print(message)
            message = message.split('|')
            now = time.time()
            hostDelay = now - float(message[1])
            if hostDelay < 0:
                hostDelay = - hostDelay
        except Exception:
            position = 0
            for sock in carSock:
                if so == sock:
                    break
                position += 1
            for sock in clientSock:
                sock.send(('close|' + '%s|' % position).encode('utf-8'))
            print("出现异常，关闭与车辆%s连接" % position)
            carAccount -= 1
            print("现有车辆数：%s" % carAccount)
            so.close()
            break

        if data:
            carid = int(message[2])
            carRound = int(message[3])
            if clientAccount == 0:
                receiveRo[carid].servernum = receiveRo[carid].servernum - receiveRo[
                    carid].arrival + 1
                receiveRo[carid].arrival = 0
                receiveRo[carid].receiveround += 1
                events[carid].set()
            else:
                time.sleep(2)
                events[carid].set()
                receiveRo[carid].servernum = receiveRo[carid].servernum - receiveRo[
                    carid].arrival + 1
                receiveRo[carid].arrival = 0
                receiveRo[carid].receiveround += 1
            events[carid].wait()
            print("compare[carid:%s]:" % carid, end="")
            print(compare[carid])
            print("hostdelay is :%s" % hostDelay)
            if not compare[carid]:
                bestid = 10
            else:
                mindelay = compare[carid][0][1]
                mindelayid = compare[carid][0][0]
                for i, v in compare[carid]:
                    if mindelay > v:
                        mindelay = v
                        mindelayid = i
                    elif mindelay == v:
                        if serving[carid] == clients[i]:
                            mindelay = v
                            mindelayid = i

                if mindelay > hostDelay:
                    bestid = 10
                elif mindelay == hostDelay:
                    if serving[carid] == clients[mindelayid]:
                        bestid = mindelayid
                    else:
                        bestid = 10
                else:
                    bestid = mindelayid
            print('best id is:%s' % bestid)
            if not serving[carid]:
                if bestid == 10:
                    so.send(("best|" + str(serverHost)).encode('utf-8'))
                    serving[carid] = serverHost
                    print(" first the best is " + str(serverHost))
                else:
                    so.send(("best|" + str(clients[bestid])).encode('utf-8'))
                    serving[carid] = clients[bestid]
                    print("first the best is " + str(clients[bestid]))
            else:
                if bestid == 10:
                    if serving[carid] == serverHost:
                        print("now serving is best")
                    else:
                        so.send(("best|" + str(serverHost)).encode('utf-8'))
                        serving[carid] = serverHost
                        print("the best is" + str(serverHost))
                else:
                    if serving[carid] == clients[bestid]:
                        print("now serving is best")
                    else:
                        so.send(("best|" + str(clients[bestid])).encode('utf-8'))
                        serving[carid] = clients[bestid]
                        print("the best is " + str(clients[bestid]))
            compare[carid] = []
            events[carid].clear()


def tcpserverReCli(so):
    global receiveRo
    global serving
    global clientAccount
    global hostDelay
    global clients
    global compare
    global serverHost
    global events
    global carStatus
    global carSock
    while True:
        try:
            data = so.recv(5120)
        except Exception:
            print("出现异常，关闭与此客户端连接")
            clientAccount -= 1
            print("现有客户机有：%s" % clientAccount)
            message = data.decode('utf-8')
            print(message)
            message = message.split('|')
            events[int(message[1])].set()
            break
        if data:
            message = data.decode('utf-8')
            print(message)
            message = message.split('|')
            if message[0] == 'status':
                for car in carSock:
                    if car in carSock:
                        if car[0] == message[7]:
                            carStatus[carSock.index(car)]._count = int(message[1])
                            carStatus[carSock.index(car)].turn = int(message[2])
                            carStatus[carSock.index(car)].curr_status = int(message[3])
                            carStatus[carSock.index(car)].forward_count = int(message[4])
                            carStatus[carSock.index(car)].forward_count_phase2 = int(message[5])
                            carStatus[carSock.index(car)].padding_from = int(message[6])
                            carStatus[carSock.index(car)].id = carSock.index(car)
                            carStatus[carSock.index(car)].address = message[7]
                            if clientSock:
                                for sock in clientSock:
                                    sock.send(('status|' + carStatus[carSock.index(car)].change()).encode('utf-8'))
                            break
            else:
                print("receive  client delay,id = %s" % int(message[4]) + ",server for car%s" % int(message[1]))
                print(message[3])
                print(receiveRo[int(message[1])].receiveround)
                if int(message[3]) != receiveRo[int(message[1])].receiveround:
                    if int(message[3]) < receiveRo[int(message[1])].receiveround:
                        break
                    else:
                        receiveRo[int(message[1])].receiveround = int(message[3])
                        receiveRo[int(message[1])].servernum = int(message[3]) - 1
                receiveRo[int(message[1])].arrival += 1
                receiveRo[int(message[1])].servernum += 1
                carid = int(message[1])
                clientid = int(message[4])
                clientdelay = float(message[2])
                compare[carid].append([clientid, clientdelay])
                print("start compare")


# 副主机
global timeDelay
global times
global carid
global myid
global getCar
global ownSock


class startServerClientSend(threading.Thread):
    def __init__(self, sockTcps):
        threading.Thread.__init__(self)
        self.sock = sockTcps
        self.sock.send("client".encode('utf-8'))

    def run(self):
        global timeDelay
        global times
        global carid
        global myid
        global ownSock
        ownSock = self.sock
        while True:
            try:
                event1.wait()
                perform, cpunum = CPU.initParameter()
                print("own delay is:%s" % timeDelay)
                self.sock.send(
                    ("%s|" % perform + "%s|" % carid + "%s|" % timeDelay + "%s|" % times + "%s" % myid).encode('utf-8'))
                event1.clear()
            except Exception:
                break


class startServerClientReceive(threading.Thread):
    def __init__(self, sockTcpr):
        threading.Thread.__init__(self)
        self.sock = sockTcpr

    def run(self):
        global myid
        global someError
        global getCar
        global carStatus
        getCar = []
        while True:
            try:
                data = self.sock.recv(5120)
                if data:
                    message = data.decode('utf-8')
                    message = message.split('|')
                    if message[0] == 'id':
                        myid = int(message[1])
                    elif message[0] == 'analysis':
                        listenPort = int(message[1])
                    elif message[0] == 'close':
                        print("请关闭对小车%s的服务" % (int(message[1])))
                    elif message[0] == 'status':
                        if not carStatus:
                            status = InterStatus()
                            status._count = int(message[1])
                            status.turn = int(message[2])
                            status.curr_status = int(message[3])
                            status.forward_count = int(message[4])
                            status.forward_count_phase2 = int(message[5])
                            status.padding_from = int(message[6])
                            status.address = message[7]
                            status.id = int(message[8])
                            carStatus.append(status)
                        else:
                            for car in carStatus:
                                if car.id == int(message[8]):
                                    have = True
                                else:
                                    have = False
                            if have:
                                for car in carStatus:
                                    if car.id == int(message[8]):
                                        car._count = int(message[1])
                                        car.turn = int(message[2])
                                        car.curr_status = int(message[3])
                                        car.forward_count = int(message[4])
                                        car.forward_count_phase2 = int(message[5])
                                        car.padding_from = int(message[6])
                                        pass
                            else:
                                status = InterStatus()
                                status._count = int(message[1])
                                status.turn = int(message[2])
                                status.curr_status = int(message[3])
                                status.forward_count = int(message[4])
                                status.forward_count_phase2 = int(message[5])
                                status.padding_from = int(message[6])
                                status.address = message[7]
                                status.id = int(message[8])
                                carStatus.append(status)
                        print(status.change())
                    print(data.decode('utf-8'))
            except Exception:
                print("服务器出现异常")
                self.sock.close()
                event1.set()
                sockError = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                sockError.sendto('error'.encode('utf-8'), ('127.0.0.1', 2400))
                sockError.sendto('error'.encode('utf-8'), ('127.0.0.1', 2401))
                time.sleep(6)
                reStart()
                break


global event1
event1 = threading.Event()
global someError
someError = False
global carStatus
carStatus = []


class getCarStatusCli(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.bind(("127.0.0.1", 5200))
        self.sock.listen(10)

    def run(self):
        global carStatus
        global ownSock
        while True:
            sock, client = self.sock.accept()

            def __get_car_status_cli():
                while True:
                    try:
                        data = sock.recv(1024)
                    except Exception:
                        print("接收status出现异常")
                        sock.close()
                        break
                    if data:
                        theStatus = pickle.loads(data)
                        if type(theStatus) == str:
                            message = theStatus.split('|')
                            if message[0] == 'status':
                                for car in carStatus:
                                    if car.address == message[1]:
                                        sock.send(pickle.dumps(car))
                                        break
                        else:
                            if ownSock:
                                ownSock.send(('status|' + theStatus.change()).encode('utf-8'))
                                print("发送")

            threading.Thread(target=__get_car_status_cli).start()


class startListenCar(threading.Thread):
    def __init__(self, sockUdp):
        threading.Thread.__init__(self)
        self.sock = sockUdp

    def run(self):
        global timeDelay
        global carid
        global times
        global livingCar
        times = 0
        global someError
        while True:
            data, caradd = self.sock.recvfrom(5120)
            message = data.decode("utf-8")
            if message == 'error':
                event1.clear()
                someError = False
                break
            message = message.split("|")
            if times != int(message[2]):
                print(data.decode('utf-8'))
                now = time.time()
                carid = int(message[0])
                if carid not in livingCar:
                    livingCar.append(carid)
                while len(carStatus) <= carid:
                    carStatus.append(-1)
                timeDelay = now - float(message[1])
                if timeDelay < 0:
                    timeDelay = - timeDelay
                times = int(message[2])
                event1.set()


def tcpSerStart(serverHost):
    thread = startServerHost(serverHost)
    thread1 = serverSendOwn(serverHost)
    thread.start()
    thread1.start()


def tcpCliStart(serverHost):
    sockTcpc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sockTcpc.connect(serverHost)
    sockUdp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sockUdp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sockUdp.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    sockUdp.bind(('0.0.0.0', 2400))
    thread1 = startServerClientSend(sockTcpc)
    thread2 = startServerClientReceive(sockTcpc)
    thread3 = startListenCar(sockUdp)
    thread1.start()
    thread2.start()
    thread3.start()


global event
global isBest
global serverHost
event = threading.Event()


def reStart():
    startConsist()


def startConsist():
    global event
    global isBest
    global serverHost
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    sock.bind(('0.0.0.0', 2200))
    performance, cpuNumber = CPU.initParameter()
    thread3 = chooseSendThread(performance=performance, cpuNumber=cpuNumber, sock=sock)
    thread4 = chooseReceiveThread(performance=performance, cpuNumber=cpuNumber, sock=sock)
    thread3.start()
    thread4.start()
    event.wait()
    time.sleep(5)
    sock.close()
    if isBest:
        getCarStatusSer().start()
        tcpSerStart(serverHost)
    else:
        time.sleep(2)
        tcpCliStart(serverHost)
        getCarStatusCli().start()
    event.clear()


if __name__ == '__main__':
    startConsist()
